using System;
using System.Linq;
using System.Xml.Linq;
using Coderoom.ScrumPlanner.Data.Contracts;
using Coderoom.ScrumPlanner.Domain;
using Coderoom.ScrumPlanner.Utilities;

namespace Coderoom.ScrumPlanner.Data.Repositories.Xml
{
	public sealed class XmlUserStoryRepository : XmlRepository, IUserStoryRepository
	{
		public override string DataFileName
		{
			get { return "UserStories.xml"; }
		}

		#region IUserStoryRepository Members

		public UserStoryCollection GetUserStories(Guid themeId)
		{
			Lock.EnterReadLock();

			try
			{
				var result = GetUserStoriesInternal().Where(userStory => userStory.ThemeId == themeId).ToArray();
				return new UserStoryCollection(result);
			}
			finally
			{
				Lock.ExitReadLock();
			}
		}

		public UserStory GetUserStory(Guid userStoryId)
		{
			Lock.EnterReadLock();

			try
			{
				return GetUserStoriesInternal().Where(userStory => userStory.Id == userStoryId).SingleOrDefault();
			}
			finally
			{
				Lock.ExitReadLock();
			}
		}

		public void CreateUserStory(UserStory userStory)
		{
			Lock.EnterWriteLock();

			try
			{
				userStory.Id = Guid.NewGuid();

				var userStoryData = ReadXml();
				// ReSharper disable PossibleNullReferenceException
				userStoryData.Root.Add(new XElement("UserStory", new XAttribute("id", userStory.Id), new XAttribute("themeId", userStory.ThemeId), new XElement("Title", userStory.Title), new XElement("Slug", userStory.Slug)));
				// ReSharper restore PossibleNullReferenceException
				WriteXml(userStoryData);
			}
			finally
			{
				Lock.ExitWriteLock();
			}
		}

		public bool DeleteUserStory(Guid userStoryId)
		{
			Lock.EnterWriteLock();

			try
			{
				var userStoryData = ReadXml();

				var userStoryToDelete = userStoryData.ImmediateDescendants("UserStory").Where(userStory => userStory.ReadAttributeAsGuid("id") == userStoryId).SingleOrDefault();

				if (userStoryToDelete != null)
				{
					userStoryToDelete.Remove(); // removes it from parent
					WriteXml(userStoryData);
					return true;
				}

				return false;
			}
			finally
			{
				Lock.ExitWriteLock();
			}
		}

		#endregion

		private IQueryable<UserStory> GetUserStoriesInternal()
		{
			var userStoryData = ReadXml();

			return (from userStory in userStoryData.ImmediateDescendants("UserStory")
			        select new UserStory {Id = userStory.ReadAttributeAsGuid("id"), ThemeId = userStory.ReadAttributeAsGuid("themeId"), Title = userStory.ReadChildValue("Title"), Slug = userStory.ReadChildValue("Slug")}).
				AsQueryable();
		}
	}
}